package org.hswebframework.example.crud.service;

import org.hswebframework.example.crud.entity.Product;
import org.omg.CORBA.MARSHAL;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.*;

@Service
public class GroupAggService {

    /**
     * 分组聚合
     *
     * @param <T>           元素类型Class
     * @param listToDeal    待分组的数据，相当于SQL中的原始表
     * @param clazz         带分组数据元素类型
     * @param groupBy       分组的属性名称
     * @param aggregatorMap 聚合器，key为聚合器名称，作为返回结果中聚合值map中的key
     * @return
     * @throws NoSuchFieldException
     * @throws SecurityException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public <T> Map<Object,Map<String,Object>> groupByProperty(List<T> listToDeal, Class<Product> clazz,
                                                              String groupBy, Map<String,Aggregator<T>> aggregatorMap) throws NoSuchFieldException, IllegalAccessException {
        Map<Object, Collection<T>> groupResult = new HashMap<Object, Collection<T>>() ;
        Field field = clazz.getDeclaredField(groupBy);
        field.setAccessible(true);
        for(T ele : listToDeal){
            Object key = field.get(ele);
            if (!groupResult.containsKey(key)) {
                groupResult.put(key,new ArrayList<T>());
            }
            groupResult.get(key).add(ele);
        }
        return invokeAggregators(groupResult,aggregatorMap);
    }

    public <T> Map<Object,Map<String,Object>> invokeAggregators(Map<Object,Collection<T>> groupResult,Map<String,Aggregator<T>> aggregatorMap){

        Map<Object, Map<String,Object>> aggResult = new HashMap<>();
        for(Object key: groupResult.keySet()){
            Collection<T> group = groupResult.get(key);
            Map<String, Object> aggValues = doInvokeAggregators(group,aggregatorMap);
            aggResult.put(key,aggValues);
        }
        return aggResult;
    }

    public <T> Map<String,Object> doInvokeAggregators(Collection<T> group , Map<String, Aggregator<T>> aggregatorMap){
        Map<String,Object> aggResult = new HashMap<>();
        for(String key : aggregatorMap.keySet()){
            Aggregator<T> aggregator= aggregatorMap.get(key);
            Object aggValue = aggregator.aggregate(key, (List<T>) group);
            aggResult.put(key,aggValue);
        }
        return aggResult;
    }
}
